unit uItemDetailsDownloadThread;

interface
uses
  Classes,
  SysUtils,
  TypInfo,
  Variants,

  DB,
  nxdb,
  ShoppingServiceXMLClasses,
  EbayConnect, uTypes,
  Forms, IdThread, IdSync, uThreadSync, IdComponent;

type

  TDownloadItemDetailsThread =  class(TidThread)
  private
     // Private declarations
     FForm        : TForm;
     FOperationResult : AckCodeType;
     FErrorRecord   : eBayAPIError;
     FEItemId       : string;
     RecAdded       : Integer;
     FSyncObj       : TFTSync;
     FRxDelta       : Integer;
     FTxDelta       : Integer;
     FItemsToGet    : TStringList;
     FEbayShoppingConnect  : TEbayShoppingConnect;
     FGetMultipleItems     : TGetMultipleItems;
     FQuery       : TnxQuery;
     FQueryItems  : TnxQuery;
     FAppID       : string;
     FSiteID      : SiteCodeType;
     FGlobalID    : Global_ID;
     FUpdateRec   : TDownloadImageThreadStatus;
     FCounter     : Integer;
     FCounterAll  : Integer;
     FBasePath    : string;
     FMultiThread : Boolean;
     FFirsImage   : string;
     FFirstURL    : string;
     FDetailDC    : TObject;
     FDebug       : Boolean;
     FUpdate      : Boolean;
     Fdc          : Char;
  protected
     // Protected declarations
     procedure GetMultipleItemsAPIError(Sender: TObject; ErrorRecord: eBayAPIError);
     procedure GetMultipleItemsEndRequest(Sender: TObject);
     procedure GetMultipleItemsStartRequest(Sender: TObject);
     procedure WriteEbayApiExceptionLog(E : Exception);
     procedure SetItemsToGet(Value : TStringList);
     procedure SetGlobalID(Value : Global_ID);
     procedure EbayShoppingConnectWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
  public
     // Public declarations
     TID                   : Integer;
     // Objects visible outside threads
     property SiteID     : SiteCodeType read FSiteID;
     property AppID      : string read FAppID write FAppID;
     property GlobalID   : Global_ID read FGlobalID write SetGlobalID;
     property ItemsToGet : TStringList read FItemsToGet write SetItemsToGet;
     property MultiThread : Boolean read FMultiThread write FMultiThread;
     property FirstImageID : string read FFirsImage write FFirsImage;
     property FirstImageUrl : string read FFirstURL write FFirstURL;
     property IDetailDC : TObject read FDetailDC write FDetailDC;
     property Debug : Boolean read FDebug write FDebug;
     property Update : Boolean read FUpdate write FUpdate;
     property DecimalSeparator : Char read Fdc write Fdc;
     // methods
     constructor Create;
     destructor Destroy; override;
     procedure Run; override;
     procedure WriteToDB;
     procedure UpdateDetails;
  end;

implementation

uses functions, ActiveX, IdHTTP, uMain, HotLog, Math;

{ TCompleteCheckThread }

constructor TDownloadItemDetailsThread.Create;
begin
  inherited Create;
  FEbayShoppingConnect  := TEbayShoppingConnect.Create(nil);
  FEbayShoppingConnect.OnWork := EbayShoppingConnectWork;
  FEbayShoppingConnect.AppID := FAppID;
  FGlobalID := EBAY_US;
  FSiteID := GlobalID2SiteCode(FGlobalID);
  FEbayShoppingConnect.SiteID := FSiteID;
  FQueryItems := TnxQuery.Create(nil);
  FQueryItems.Database := fmMain.nxdtbs1;
  FItemsToGet := TStringList.Create;
  FSyncObj := TFTSync.Create(Self);
  FBasePath := fmMain.BasePath;
  FreeOnTerminate := True;
  FMultiThread := True;
  FFirsImage := '';
  IDetailDC := nil;
  FDebug := False;
  FUpdate := False;
  Fdc := '.';
end;

destructor TDownloadItemDetailsThread.Destroy;
begin
  FreeAndNil(FEbayShoppingConnect);
  FreeAndNil(FItemsToGet);
  FreeAndNil(FSyncObj);
  FreeAndNil(FQueryItems);
  inherited;
end;

procedure TDownloadItemDetailsThread.EbayShoppingConnectWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
  case AWorkMode of
  wmRead  : begin
    FSyncObj.OnHttpWork(AWorkMode,AWorkCount-FRxDelta);
    FRxDelta := AWorkCount;
  end;
  wmWrite : begin
    FSyncObj.OnHttpWork(AWorkMode,AWorkCount-FTxDelta);
    FTxDelta := AWorkCount;
  end;
  end;
end;

procedure TDownloadItemDetailsThread.GetMultipleItemsAPIError(Sender: TObject;
  ErrorRecord: eBayAPIError);
var i : Integer;
begin
  with ErrorRecord  do begin
    hLog.AddError(0,'ApiCall: GetMultipleItems. API Error',[ShortMessage, LongMessage,ErrorCode,SeverityCode,ErrorClassification,index]);
  end;
  hLog.Add('Request XML');
  for i := 0 to FEbayShoppingConnect.RequestXMLText.Count -1 do hLog.Add(FEbayShoppingConnect.RequestXMLText.Strings[i]);
  hLog.Add('Response XML');
  for i := 0 to FEbayShoppingConnect.ResponseXMLText.Count -1 do hLog.Add(FEbayShoppingConnect.ResponseXMLText.Strings[i]);
end;

procedure TDownloadItemDetailsThread.GetMultipleItemsEndRequest(Sender: TObject);
begin
  hLog.Add(Format('{hms} ApiCall: GetMultipleItems. Result %s',[GetEnumName(TypeInfo(AckCodeType),ord(FGetMultipleItems.Ack))]));
  if FDebug then FGetMultipleItems.ResponseXMLDoc.SaveToFile('GetMultipleItemsResponse.xml');
  FSyncObj.IncApiUsage;
end;

procedure TDownloadItemDetailsThread.GetMultipleItemsStartRequest(
  Sender: TObject);
begin
  hLog.Add('{hms} ApiCall: GetMultipleItems. Starting');
  if FDebug then FGetMultipleItems.RequestXMLDoc.SaveToFile('GetMultipleItemsRequest.xml');
end;

procedure TDownloadItemDetailsThread.Run;
var i : Integer;
    hr: HRESULT;
    cnt : Integer;
begin
  inherited;
  try
    hr := CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
    if hr <> S_OK then Exception.Create('Error occurs: ' + IntToHex(hr, 2));
    FGetMultipleItems := TGetMultipleItems.Create(nil);
    FGetMultipleItems.OnAPIError := GetMultipleItemsAPIError;
    FGetMultipleItems.OnStartRequest := GetMultipleItemsStartRequest;
    FGetMultipleItems.OnEndRequest := GetMultipleItemsEndRequest;
    FGetMultipleItems.Connector := FEbayShoppingConnect;
    if not FUpdate then FGetMultipleItems.IncludeSelector := [Details,ItemSpecifics,Description]
    else FGetMultipleItems.IncludeSelector := [Details,ItemSpecifics];
    if FUpdate then begin
      FQueryItems.SQL.Add('SELECT Items.ItemID');
      FQueryItems.SQL.Add('FROM Items');
      FQueryItems.SQL.Add('WHERE Items.Enabled = true');
    end
    else begin
      FQueryItems.SQL.Add('SELECT TOP 19 Items.ItemID');
      FQueryItems.SQL.Add('FROM Items');
      FQueryItems.SQL.Add('WHERE Items.PictureURL Is Null');
    end;
    try
      FItemsToGet.Clear;
      if not FUpdate then FItemsToGet.Add(FFirsImage);
      FQueryItems.Open;
      if FQueryItems.RecordCount >0 then begin
        while not FQueryItems.Eof do begin
          FItemsToGet.Add(FQueryItems.FieldValues['ItemID']);
          FQueryItems.Next;
        end;
        FEbayShoppingConnect.AppID := FAppID;
        FEbayShoppingConnect.SiteID := FSiteID;
        repeat
          cnt := min(19,FItemsToGet.Count-1);
          FGetMultipleItems.ItemID.Clear;
          for i := 0 to cnt do FGetMultipleItems.ItemID.Add(FItemsToGet.Strings[i]);
          try
            FRxDelta := 0;
            FTxDelta := 0;
            FOperationResult := FGetMultipleItems.DoRequestEx;
            if (FOperationResult in [Failure, PartialFailure]) then begin
              Exception.Create('Request Failure');
            end;
            //FSyncObj.WriteLog('GetMultipleItems request done. Result: '+GetEnumName(TypeInfo(AckCodeType),ord(FOperationResult)));
            hLog.Add('{hms} GetMultipleItems request done. Result: '+GetEnumName(TypeInfo(AckCodeType),ord(FOperationResult)));
            if Terminated then Exit;
            if FOperationResult in [Success, Warning, PartialFailure] then begin
              FCounterAll := 0;
              FCounter := 0;
              if FUpdate then UpdateDetails else WriteToDB;
              FUpdateRec.TotalItems := FCounterAll;
              FUpdateRec.SavedPhotos := FCounter;
              FSyncObj.UpdDThreadStatus(FUpdateRec);
            end;
            if (FOperationResult in [Failure, Warning, PartialFailure]) then
              with FSyncObj do begin
                hLog.AddError(0,'GetMultipleItems Request failure',[GetEnumName(TypeInfo(AckCodeType),ord(FOperationResult))]);
                hLog.Add('Request XML');
                for i := 0 to FEbayShoppingConnect.RequestXMLText.Count -1 do hLog.Add(FEbayShoppingConnect.RequestXMLText.Strings[i]);
                hLog.Add('Response XML');
                for i := 0 to FEbayShoppingConnect.ResponseXMLText.Count -1 do hLog.Add(FEbayShoppingConnect.ResponseXMLText.Strings[i]);
              end;
          except
            on E : Exception do WriteEbayApiExceptionLog(E);
          end;
          if Terminated then Stop;
          for i := 0 to cnt do begin
            FItemsToGet.Delete(0);
          end;
        until FItemsToGet.Count = 0;
      end
      else Stop;
    finally
      FQueryItems.Close;
    end;
  finally
    CoUninitialize;
    FreeAndNil(FGetMultipleItems);
    Stop;
  end;
end;

procedure TDownloadItemDetailsThread.WriteEbayApiExceptionLog(E: Exception);
var i : Integer;
begin
  hLog.AddException(E,'GetMultipleItems',[]);
  hLog.Add('Request XML');
  for i := 0 to FEbayShoppingConnect.RequestXMLText.Count -1 do hLog.Add(FEbayShoppingConnect.RequestXMLText.Strings[i]);
  hLog.Add('Response XML');
  for i := 0 to FEbayShoppingConnect.ResponseXMLText.Count -1 do hLog.Add(FEbayShoppingConnect.ResponseXMLText.Strings[i]);
end;

procedure TDownloadItemDetailsThread.WriteToDB;
var i,j: Integer;
    ItemDetails : TItemDetails;
begin
  try
    for i:=0 to FGetMultipleItems.Items.Count-1 do
    with FGetMultipleItems.Items.Items[i] do begin
      inc(FCounterAll);
      ItemDetails.PaymentMethods := '';
      ItemDetails.ShipToLocations := '';
      ItemDetails.PictureURL := No_Photo;
      ItemDetails.ItemID := ItemID;
      ItemDetails.Description := Description;
      for j:=0 to PaymentMethods.Count-1 do ItemDetails.PaymentMethods := ItemDetails.PaymentMethods + ',' + PaymentMethods[j];
      if Length(ItemDetails.PaymentMethods)>0 then ItemDetails.PaymentMethods := Copy(ItemDetails.PaymentMethods,2,Length(ItemDetails.PaymentMethods)-1);
      for j:=0 to ShipToLocations.Count-1 do ItemDetails.ShipToLocations := ItemDetails.ShipToLocations + ',' + ShipToLocations[j];
      if Length(ItemDetails.ShipToLocations)>0 then ItemDetails.ShipToLocations := Copy(ItemDetails.ShipToLocations,2,Length(ItemDetails.ShipToLocations)-1);
      if ChildNodes.FindNode('PictureURL') <> nil then begin
      //if PictureURL <> nil then begin
        try
          ItemDetails.PictureURL := PictureURL[0];
        except
          ItemDetails.PictureURL := No_Photo;
        end;
      end;
      // try save photo url
      if FFirsImage = ItemID then FFirstURL := ItemDetails.PictureURL;
      FSyncObj.SavePictureDetails(ItemDetails);
      inc(FCounter);
      //**************
      // end try download photos
    end;
  except
    on E : Exception do
    begin
      hLog.AddException(E,'Save database GetMultipleItems',[ItemDetails.ItemID]);
    end;
  end;
end;

procedure TDownloadItemDetailsThread.UpdateDetails;
var i: Integer;
    ItemDetails : TItemDetails;
begin
  try
    for i:=0 to FGetMultipleItems.Items.Count-1 do
    with FGetMultipleItems.Items.Items[i] do begin
      inc(FCounterAll);
      ItemDetails.BidCount := BidCount;
      ItemDetails.ItemID := ItemID;
      ItemDetails.ListingStatus := ListingStatus;
      ItemDetails.QuantitySold := QuantitySold;
      //if not VarIsNull(ReserveMet)  then ItemDetails.ReserveMet := ReserveMet;
      ItemDetails.BidCount := BidCount;
      if Fdc = '.' then
        ItemDetails.Price := StrToFloat(CurrentPrice.NodeValue)
      else
        ItemDetails.Price := StrToFloat( StringReplace(CurrentPrice.NodeValue,'.',Fdc,[]));
      ItemDetails.PriceCurrency := CurrentPrice.CurrencyID;
      FSyncObj.UpdateItemDetails(ItemDetails);
      inc(FCounter);
      //**************
      // end try update details
    end;
  except
    on E : Exception do
    begin
      hLog.AddException(E,'Save database GetMultipleItems',[ItemDetails.ItemID]);
    end;
  end;
end;

procedure TDownloadItemDetailsThread.SetItemsToGet(Value : TStringList);
begin
  if Value <> nil then FItemsToGet.Assign(Value);
end;

procedure TDownloadItemDetailsThread.SetGlobalID(Value : Global_ID);
begin
  FGlobalID := Value;
  FSiteID := GlobalID2SiteCode(FGlobalID);
  FEbayShoppingConnect.SiteID := FSiteID;
end;

initialization
  Randomize;

end.
